﻿/************************************************
*Author: KIM
*Create Time: 2/15/2017 09:54:54
*CLR Version: 4.0.30319.42000
*Description:
*
*Update History:
*
***********************************************/

using Microsoft.CSharp;
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;

namespace ACC.Extensions.Utilities
{
    public class CompileHelper
    {
        public static string[] ReferenceAssemblies = new string[]
        {
            "System.dll",
            "System.Core.dll",
            "System.Data.dll",
            "System.Xml.dll",
            "iPlant.Framework.ACC.WCF.dll",
            "ACC.Extensions.Entities.dll",
            "ACC.Extensions.ClientBusiness.dll",
            "ACC.Extensions.Utilities.dll"
        };

        private static readonly string _tempDir = 
            Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, "_temp");

        public static Assembly CompileScriptToAssembly(string sourceCode, bool generateInMemory = false)
        {
            CompilerParameters param = new CompilerParameters();
            param.ReferencedAssemblies.AddRange(ReferenceAssemblies);
            param.GenerateInMemory = generateInMemory;
            
            if(!generateInMemory)
            {
                if(!Directory.Exists(_tempDir))
                {
                    Directory.CreateDirectory(_tempDir);
                }
                param.TempFiles = new TempFileCollection(_tempDir);
            }
            param.IncludeDebugInformation = true;
            CodeDomProvider provider = new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v3.5" } });
            CompilerResults result = provider.CompileAssemblyFromSource(param, sourceCode);
            if(result.Errors.HasErrors)
            {
                StringBuilder sb = new StringBuilder();
                foreach(var error in result.Errors)
                {
                    sb.AppendLine(error.ToString());
                }
                throw new Exception(sb.ToString());
            }
            return result.CompiledAssembly;
        }

        public static Type CompileScript(string sourceCode, string typeName, bool generateInMemory = false)
        {
            CompilerParameters param = new CompilerParameters();
            param.ReferencedAssemblies.AddRange(ReferenceAssemblies);
            param.GenerateInMemory = generateInMemory;
            if(!generateInMemory)
            {
                if(!Directory.Exists(_tempDir))
                {
                    Directory.CreateDirectory(_tempDir);
                }
                param.TempFiles = new TempFileCollection(_tempDir);
            }
            param.IncludeDebugInformation = true;
            param.CompilerOptions = "/debug:pdbonly /noconfig /nowarn:1701,1702 /platform:x86 /define:TRACE;DEBUG";
            CodeDomProvider provider = new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v3.5" } });
            CompilerResults result = provider.CompileAssemblyFromSource(param, sourceCode);
            if(result.Errors.HasErrors)
            {
                StringBuilder sb = new StringBuilder();
                foreach(var error in result.Errors)
                {
                    sb.AppendLine(error.ToString());
                }
                throw new Exception(sb.ToString());
            }
            return result.CompiledAssembly.GetType(typeName);
        }
    }
}
